Review

Course Done: How was it?

CONS: Who says "movie" of a 4 minute video, this guy's vocabulary is mad.

PROS:
Was he good? Yes, he is good THE COURSE IS GOOD.
He does not overwhelm you with jack tons of completely miniscule details of every single feature a language has. The course is "Javascript ESSENTIAL" and the title wasn't a LIE! You genuinely learn the essential concepts so at the end of the course, you finally get things now.

There are mini exercises that proves and test if you genuinely understood what he was saying. Every coding exercises are in the context of what he taught in that specific and a mix of preceding chapters.

He uses ANALOGY and VISUAL representations at time


HTML CODE - Order loading of Javascript inside of HTML Code matters

Remember that the browser renders HTML file from top to bottom

Loading Script ERROR:

  1. Css Load
  2. Script Run
  3. HTML <body> load
    So it says grab the document.
    Then find the body element inside the document and then appendChild.
    The problem is in the HTML document, the script is run before the body element is created.
    The error is telling me the script can't get access to the body element because the body element was never created.
    It can't do what the JavaScript is trying to do, because the elements don't yet exist.

A SHIT SOLUTION (explained later why it's shit)
To fix this, I can then take the script tag entirely and paste it in below the body element.

  1. CSS Load
  2. HTML <body> load
  3. Script Run
    There are no errors in the console, and the content is displaying as it should.
    This is not a solution though, this is a hack, and it introduces a whole range of other problems, there's a good chance you have JavaScript that should run at the beginning, or should happen, while the document is being loaded.

Loading JavaScript in the footer, is now an anti pattern.
From here on forward, JavaScript should always be loaded in the head, and then you use async or defer, to control when that JavaScript is executed on the document.

Abstract - Difference between Async and Defer

The only difference between the two is when the JS file is executed

  • async (after JS Downloaded)
  • defer (after both HTML parsed and js downloaded)

Render Blocking - HTML

“render_blocking.png” could not be found.
Can also be called CONTENT Blocking
So this is the default behavior.
This is called content or render blocking, because it quite literally, blocks the rendering of the content in the page. And it can cause all sorts of weird problems, like what you saw in my example, and it also causes the page to just load slower, and it's not a great solution.

Async Keyword - HTML

“async.png” could not be found.
The async keyword changes this behavior significantly.

  1. Simultaneously do
    HTML Parsing
    DOWNLOADING JS FILE

  2. Execute JS FILE only if
    JS Downloaded DONE
    Also, temporarily PAUSE HTML parsing

  3. Continue HTML Parsing
    After JS Execution

This is good for some purposes, especially when you need, to

  • get the JavaScript to parse as quickly as possible,
  • and you don't really care about render blocking.

Defer keyword - HTML

“defer.png” could not be found.
The defer keyword

  1. Simultaneously do
    HTML Parsing
    DOWNLOADING JS File

  2. Execute JS File after both are done:
    HTML Parsed DONE
    JS Downloaded DONE
    Or ALL resources have been parsed/downloaded

What happens when you defer JavaScript?
The browser loads the JavaScript asynchronously when it is encountered, then waits until all HTML is rendered before executing the script.

JS Problem - File gets very large and bulky code

As you start working with JavaScript,
you'll quickly notice these files tend to get really large and kind of hard to work with.
To solve this problem, we now have something called JavaScript modules.

Javascript Modules

Now to get this to work in practice, you have to do one more thing.
Inside index.html, you need to tell the browser,

  • first of all there are two files now.
  • And second of all, these two files on our modules, they may rely on each other and it's important that they're both loaded before things work properly.
    Setting the type attributes to module, both files automatically get deferred
    So modules only run after everything else has happened to ensure that the browser has all the modules available before anything gets rendered out. (Comment: Makes sense)

Javascript Objects

Javascript - In calling properties in an object. Properties is what we use to describe an object
Two ways

  • bracket notation myObject.["property"]
  • dot notation myObject.property

Object is defined with curly braces around it along with its properties or optionally methods

const objectDemo = {
  dance: "Mambo",
  number: "5",
}

A method is actually just a function inside of an object. A method is a verb

Okay wtf, these are the same thing

class Name {}        // Class Declaration
const Name = class{} // Class Expression

Questions:
What does the this keyword refer to in a class?
-> Why is this wrong "this refers to the class constructor."
-> Why is this the correct answer "this refers to the current object created from the class."


Shortcut of Declaring Function

Example 1 Single Parameter

// Arrow function with single parameter and single expression
const double = x => x * 2;

// Equivalent traditional function expression
const double = function(x) {
    return x * 2;
};

Example 2 Multiple Parameters

// Arrow function with multiple parameters and block of code
const sum = (a, b) => {
    num = a + b
    return num;
};

// Equivalent traditional function expression
const sum = function(a, b) {
    num = a + b
    return a + b;
};

Example 3 No Parameters

// Arrow function with no parameters
const getCurrentYear = () => new Date().getFullYear();

// Equivalent traditional function expression
const getCurrentYear = function() {
    return new Date().getFullYear();
};

DOM

  • Traversing up and down the DOM tree to find one or more elements is going to be something you do all the time when working with JavaScript.

Getting elements

NEW BETTER WAY

document.querySelector() // Returns the HTML snippet code
document.querySelectorAll() // Returns a NodeList (A node list containing each element object matching the query.)

Old way of getting element

document.getElementsByClassName() // Receives a string of classnames to be found as its parameter. 
document.getElementById()

innerHTML vs outerHTML
inner basically is what's inside of the element tag
outer includes the element tag, for instance

  • document.querySelector("ul").innerHTML // <ul> tag is EXcluded
  • document.querySelector("ul").outerHTML // ul tag is INCLUDED

Need to indicate a state change of an element? Add or remove a class.

A common task in JavaScript is to modify the classes of an element in some way.
This is a simple way of without having to inject CSS into the HTML itself.

  • changing the appearance (hiding and showing a panel)
  • or behavior of an element (highlighting a button)
    Instead, we just
  • add a class
  • or remove a class

Class manipulation

Class manipulation is common enough,
that we have two specialized properties for it.

The first one and the oldest one is className, and it's

  1. document.querySelector("h1").className = "new-class-name" // Assigning new value
    it's available for all elements in the dom.
    returns className holds a string, listing out all the classes appended to an element.
    The class changes because I'm reassigning the class name property.

PROBLEM - Two challenges with using className

  1. Can be redundant and uses verbose code. If you have an element with several classes like we have here in the UL, we have several elements that have several classes, you can't just replace the classes with a new class, because that way you're wiping out all the classes, you're exchanging all the content within the property for some other content. So if you have a property with several classes and you want to just change one of the classes you have to somehow go in and parse out which classes you want to keep, and which ones you want to change and it gets really clunky and requires a lot of code.
  2. Conflict in other Javascript Frameworks. In React and other JavaScript frameworks, the term class name is used in place of class in markup to avoid collisions with the JavaScript class keyword which is used to set up classes. This means if you're trying to target the class name property, but you're inside a JavaScript framework, you're actually doing something else which can cause unexpected behavior and will not result in what you want. As a result we really shouldn't be using the class name property in frameworks, and we should be careful about using the class name property anywhere else as well.

SOLUTION - classList property

To get around both of these problems, use the classList property.
returns Dom token collection of all the classes appended to an element.

Methods to manipulate individual classes

  • classList.add()
  • classList.remove()
  • classList.toggle() toggle, true or false
  • classList.replace("old_class", "new_class")

CONCLUSION: Here's the bottom line.

If you want to add, remove, toggle or replace classes you should always use the class list property, and use the methods that come with it.

If on the other hand, you're looking for a string and you want just the output of all the classes to do something else with, you can use the class name property.

Data Attribute

Need to pass data from one element to the other?

  • Add a data attribute.

What attributes return

A node map and not an array

NamedNodeMap {0: src, 1: alt, src: src, alt: alt, length: 2}
  0: src
  1: alt
  alt: alt
  src: src
  length: 2
  [[Prototype]]: NamedNodeMap

Explanation:
One thing worth noting here is the attributes property returns a different type of data
from the class name and class list properties.
What we get is a named node map and it is not an array.
So we can't use array methods on it.
There's a simple reason for this.
An attribute is a more complex piece of data, it has a key and a value and we need to be able to manipulate just the key or just the value or both at any time and a simple array wouldn't do that.

Methods for attribute

Check, Get, Set/Create and Remove
document.querySelector("img").hasAttribute("src") // Check if element has attribute
document.querySelector("img").getAttribute("src") // Get attribute
document.querySelector("img").setAttribute("alt", "value to set") // Set/Create new attribute
document.querySelector("img").removeAttribute("title")

Inline Style

Need to change the appearance of a specific element for some reason?

  • Add an inline style.

Modify, Add, Change, etc.. etc...
document.querySelector("site.title").style
document.querySelector("site.title").style.backgroundColor = "pink"

DOM Manipulation

Problem: Template Literal can be destructive

Template literal creates HTML in Javascript

  • then adds that HTML to the existing document
  • by targeting an existing element and replacing its internal HTML using the inner HTML property.

This is an effective way of injecting new HTML into a document,
but it's also rather crude and destructive.
WHY: It requires an existing element to be in the HTML documents,
and it wipes up whatever code was contained inside that element. And that can be a problem.
We're also replacing all the content inside the main element, so this new text disappears.

SOLUTION: DOM Manipulation

Let's create a new element. Uses Document.createElement()
Parameter expects a valid html element (div, p)

// Creating Element
const newArticle = document.createElement("article"); // Document.createElement()
newArticle.classList.add("backpack"); // The element is created, but has not been added to the DOM.
newArticle.setAttribute("id", "everyday");
newArticle.innerHTML = content; // content is a variable that has `html code`
// Get the value of newArticle element(which is empty for now), 
// then replace it with the variable `content`

We're going to append it now.
ParentNode.append()

// Adding the newly created element to the existing element in the DOM 
const main = document.querySelector(".maincontent")
main.append(newElement) // ParentNode.append()

Adding CREATED element to existing element

Now we've created the element, we're going to append it now.
Uses ParentNode.append()

The append method can be used to add one or several comma-separated elements and they all go inside but at the end of the parent Node.
And it can also be used to append a string of texts if that's what you want to do.
ParentNode.append()

// Adding the newly created element to the existing element 
const main = document.querySelector(".maincontent") 
main.append(newElement) // ParentNode.append()

ParentNode.prepend()
Add element to
First child of the parent,
Just places the element at the top instead of at the bottom of the parent element.

ParentNode.appendChild()
Same as .append()
Also returns this element to you.

ParentNode.replaceChild()
Replaces a child element of a parent.

ParentNode.insertBefore(newElement, parentElement)
Allows us to insert an element before the parent elements.
Add element before other elements rather than just inside them

ParentNode.insertAdjacent()
Add element after other elements rather than just inside them
Can specify exactly where you want that new element to appear,

  • inside or outside the target element.

Variables and Data Types

So, the way of seeing variables here is a container of an object. Let's say,

  • we have a container(a box)
  • named(labeled with writing) "number",
  • inside of the container(a box) is 5 (a physical number 5)

And when I say container is created I mean that pretty literally.

  • When you define a variable in JavaScript,
  • you effectively carve out space in the computer memory
  • and place something inside that space.

So basically, each time we create a variable, we're consuming a space in the ram, then we put whatever data we want inside of that consumed space.

Different Equality Operators

a = b assigns the value of b to a.
a == b tests for equality between a and b.
STRICT: a === b tests for identical equality (checks if same data type) between a and b.


Functions and Methods

Important New Term:

  • Hoisted

The term function is typically used to refer to as a function that sits on itself
a method is a function that sits inside an object and acts on that object.
They're effectively the same thing, they just appear in different contexts.

A function can be created in a couple of different ways
and how we create a function
has an impact on how it can be used.

Function Declaration

Function declaration is hoisted to the to the top of their containing scope during the compilation phase.
This means you can call a function before it's declared in the code. However, this hoisting behavior applies to the scope in which the function is declared, not necessarily the global scope.

console.log(myFunction()); 
// ^--- This works, even though myFunction is called before its declaration

function myFunction() {
    return "Hello, world!";
}
  • myFunction() is called before its declaration in the code.
  • However, because function declarations are hoisted during the compilation phase, myFunction() is available to be called from anywhere in the same scope, including before its actual declaration.
  • In JavaScript, during the compilation phase, all function declarations are hoisted to the top of their containing scope, meaning they are parsed and made available before any actual code execution occurs. This allows you to call functions anywhere in your code, even before their actual declarations

So just like a VAR,
If you create a new function and use the same name, that new function will take precedence further down in the code.
So you can accidentally override an existing function if you're using function declarations.

function myFunction() {
    console.log("First declaration");
}
myFunction(); // Output: "Second Declaration"

function myFunction() {
    console.log("Second declaration");
}
// Calling the function
myFunction(); // Output: "Second declaration"

Function Expression

const getRectArea = function (width, height) {
  return width * height;
};

So if we're using a const to store the function expression,

  • then it is locally scoped or block scoped automatically.
  • also cannot be re-declared
  • not hoisted, exists only in the scope they were created (facilitated by const)
  • typically uses Anonymous Functions
    Allows default values in the parameters

Immediately invoked function expression (IIFE)

In an IFE, we wrap an

  • anonymous function
  • or a name function
    inside parentheses

It's immediately invoked and run as soon as the browser encounters it.
Runs the function immediately without calling it

Anonymous Functions

Typically used in

  • Function Expression
  • Immediately Invoked Function Expression

Arrow function expression =>

Remember, we're saying "SHORTCUT" of Function Expression
Meaning anything that's on arrow function will not be HOISTED

PROBLEM: this keyword of a function inside of a function
Earlier, we saw that this keyword used when we created an object constructor and you may remember, this keyword can be used inside any object to refer back to the object itself. So what's happening here is this function is hoisted out of the object and up to the global scope.

SOLUTION: Arrow function
An arrow function does not have its own this
It does not know what this means
--> and it will refer to the closest available scope which in this case is the object.

This also explains why we can't use an arrow function as the declaration for a method,
because if we did that, the arrow function wouldn't know what scope to use.
So it would refer back to the global scope instead of the method scope and therefore nothing would work properly inside that arrow function.

Callbacks

In JavaScript,
a callback is a function that is passed as an argument to another function
is executed after the completion of some asynchronous operation or event.

Basically we are ==using functions as a parameter to a function
A callback is a function used as a parameter in a function

function fetchData(callback) {
    // Simulating an asynchronous operation
    setTimeout(() => {
      const data = { name: "Alice", age: 30 };
      callback(data); // The callback function is called with the fetched data
    }, 1000); // Simulating a delay of 1 second
  }

// Using the fetchData function with a callback
fetchData( 
    (result) => {
        console.log("Data received:", result);
    }
)
// ^-- The argument here is an anonymous arrow function

Notes:
Callbacks are used to manage the flow of control in scenarios where operations may take some time to complete, such as:

  • reading from a file
  • making an HTTP request
  • querying a database

Ternary Operators

A single line way of writing if else statements

Looping in Javascript

for (let i = 0; i < length; i++) {
    // code here
}

Array Based Looping

for of

for (const item of items) {
    // code here
}

array.forEach(arg: anon-arrow-function)

items.forEach(
    (item) => {
        // code here
    } 
)

Object Based Looping

for in

for (const singleObject in nestedObjects) {
  // code here
}

map(arg: anon-arrow-function) array method

const stuffItems = items.map(
    (item) => {
      // code here
      return item
    }
)

Event Listener

UPDATE: The event listener chapter isn't that good. I'd have to rely on other resources.

Everything that happens in the browser is an event.

  • Opening the browser is an event,
  • visiting a URL is an event,
  • moving your mouse or clicking it or touching your screen is an event,
  • scrolling is an event,
  • clicking the back and forth buttons in the browser
  • or reloading the document or hitting a key on your keyboard

Adding arguments in a callback function

Fuck this is confusing, I'll probably learn this a long the way

const btn = document.querySelector("button");

const lidToggle = (arg1) => {
    return arg1;
}
btn.addEventListener("click", lidToggle)

Random

undefined means there's no value in it but it's taking up space in the memory.
Remember that when you create a variable, you're creating a space in the memory.
Think of it like putting a box, that box is a variable, inside of that box will be a value
When it's undefined, the box is empty.

Like pointers but in javascript
let newDeskArr = [...deskArray];
The original array is deskArray,
now whatever we change to newDeskArr will also affect the original array
It's called "shallow copy"

With array.splice(). Provided you have the index
You can:

  • replace, array.splice(indexReplaced, 1, NewValue) // Index#, replace 1 element with this, new value"
  • remove array.splice(indexRemoved, 1) // Index#, remove 1 element
  • insert array.splice(indexAdd, 0, AddedVal) // Index#, remove none, add the new value

What is the difference between the array.forEach() and array.map() methods?
array.forEach() executes a provided callback function once for each item in the array. array.map() creates a new array with the results of executing a provided callback function once for each item in the original array.

True or false: An arrow function can be used to define an object method.
FALSE

The key to all of that was realizing, in JavaScript, everything is an object. Those objects have properties, and those objects have methods that act on those properties. And that's the lesson I've tried to share with

Questions: What is ECMAScript?
The specification describing how browsers should implement and interpret JavaScript.

An event listener can be appended to the window object.

  • TRUE
    Event listeners are often used to listen for when the document is fully loaded in the browser. For this and other window events, we append an event listener to the window object.

How do you capture the event object in an event listener?
Answer: The event object is automatically passed as a parameter to the callback function. Simply name and use the parameter.